﻿/**
* @author ring_buffer.h
* @brief 环形缓冲，可实现两个线程无锁并行的读写数据
* @author macwe1024 at gmail dot com
* @bugfix 
* 2019.11.13 by lzhkui: 修复了几处编译错误，修复了put函数、roundupPowOfTwo函数的内部实现bug 
* 2019.11.22 by lzhkui: 新增put、get重载函数，用于在剩余空间不足或有效数据长度不够时，直接放弃本次操作
* 2020.03.03 by lzhkui: 修复了get函数中，执行第二次拷贝，拷贝剩余数据至目标地址上的笔误，把目标地址写成了源地址... -#-！ 导致了用此环形缓冲的几个神奇bug...
*/

#ifndef _THEFOX_BASE_RINGBUFFER_H_
#define _THEFOX_BASE_RINGBUFFER_H_

#include <base/Types.h>

namespace thefox {

class RingBuffer
{
public:
	explicit RingBuffer(uint32_t size)
		: _in(0)
		, _out(0)
	{
		// 调整size到2的n次幂大小
		if (size & (size - 1)) {
			size = roundupPowOfTwo(size);
		}

		_size = size;

		_buffer = static_cast<char *>(malloc(_size));

	}
	~RingBuffer()
	{
		free(_buffer);
	}
	
	//！存到满为止
	uint32_t put(char *buffer, uint32_t len)
	{
		len = MIN(len, _size - _in + _out);

		// 拷贝从_in -> end
		uint32_t l = MIN(len, _size - (_in & (_size - 1)));
		memcpy(_buffer + (_in & (_size - 1)), buffer, l);
		
		// 拷贝从 begin -> 剩余的部分
		memcpy(_buffer, buffer + l, len - l);

		_in += len;

		return len;
	}

	//! 剩余空间不够存储，直接放弃本次操作
	uint32_t put(char* buffer, uint32_t len, bool) {
		if (len > _size - _in + _out) {
			return 0;
		}

		return put(buffer, len);
	}

	//！取到干为止
	uint32_t get(char *buffer, uint32_t len)
	{
		len = MIN(len, _in - _out);

		// 拷贝从_out -> end
		uint32_t l = MIN(len, _size - (_out & (_size - 1)));
		memcpy(buffer, _buffer + (_out & (_size - 1)), l);

		//拷贝剩余的
		memcpy(buffer + l, _buffer, len - l);

		_out += len;

		return len;
	}

	//! 有效数据长度小于读取长度，直接放弃本次操作
	uint32_t get(char* buffer, uint32_t len, bool) {
		if (len > _in - _out) {
			return 0;
		}

		return get(buffer, len);
	}

	uint32_t size() const { return _size; }
	uint32_t canRead() const { return _in - _out; }
	uint32_t canWrite() const { return _size - _in + _out; }
private:
	uint32_t roundupPowOfTwo(uint32_t size)
	{
		int n = 0;
		while (0 != size) {
			size >>= 1;
			++n;
		}
		
		return 1 << n;
	}

	char *_buffer;
	uint32_t _size; // ringbuffer的总大小
	uint32_t _in;   // 写数据的位置
	uint32_t _out;  // 读数据的位置
};

} // namespace thefox

#endif // _THEFOX_BASE_RINGBUFFER_H_
